package com.toe.recommend.webapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.toe.business.service.BusinessInformationService;
import com.toe.common.exception.ToeServiceException;
import com.toe.common.restful.JsonPage;
import com.toe.common.restful.StateEnum;
import com.toe.common.utils.*;
import com.toe.pojo.dto.recommend.RecommendAddClassDTO;
import com.toe.pojo.dto.recommend.RecommendClassesRedisDTO;
import com.toe.pojo.entity.business.BusinessInformation;
import com.toe.pojo.entity.recommend.RecommendClasses;
import com.toe.pojo.vo.recommend.RecommendClassesQueryVO;
import com.toe.pojo.vo.recommend.RecommendClassesVO;
import com.toe.pojo.vo.recommend.RecommendClassesVideoVO;
import com.toe.recommend.service.RecommendClassesService;
import com.toe.recommend.webapi.mapper.RecommendClassesMapper;
import com.toe.recommend.webapi.repository.IRecommendClassesRepository;
import com.toe.recommend.webapi.util.MathUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 陶涛
 * @since 2022-07-19
 */
@Service
@DubboService
@Transactional
public class RecommendClassesServiceImpl extends ServiceImpl<RecommendClassesMapper, RecommendClasses> implements RecommendClassesService {

    @DubboReference
    BusinessInformationService dubboBusinessInformationService;

    @Autowired
    RecommendClassesMapper recommendClassesMapper;

    @Autowired
    IRecommendClassesRepository repository;

    @Value("${server.port}")
    private String port;

    @Value("${file.staticVideoPatternPath}")
    private String staticVideoPatternPath;

    @Value("${file.staticVideoImgPatternPath}")
    private String staticVideoImgPatternPath;

    @Value("${file.uploadVideoFolder}")
    private String uploadVideoFolder;

//    @Autowired
//    CommodityClassesMapper commodityClassesMapper;
//
//    @Autowired
//    CommodityClassesTypeMapper commodityClassesTypeMapper;

//    @Override
//    public void insert(AddClassDTO classDTO, MultipartFile file) {
//        // 获取保存文件的相对路径
//        String videoPathDir = "F://toe/payClasses";
//        String coverPathDir = "F://toe/payClasses/image";
//        String videoPath = null;
//        String coverPath = null;
//        try {
//            videoPath = FileUtils.upload(videoPathDir, file);
//            coverPath = FileUtils.fetchFrame(videoPath, coverPathDir);
//        } catch (IOException e) {
//            if (videoPath != null) {
//                File video = new File(videoPath);
//                if (video.exists()) {
//                    video.delete();
//                }
//            }
//
//            if (coverPath != null) {
//                File cover = new File(coverPath);
//                if (cover.exists()) {
//                    cover.delete();
//                }
//            }
//
//            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
//                    "添加失败,服务器忙,请稍后重试");
//        }
//
//        LocalDateTime localDateTime = LocalDateTime.now();
//        Date date = Date.from(localDateTime
//                .atZone(ZoneId.systemDefault())
//                .toInstant());
//
//        QueryWrapper<CommodityClassesType> wrapper = new QueryWrapper<>();
//        wrapper.eq("type_name", classDTO.getType());
//        CommodityClassesType query = commodityClassesTypeMapper.selectOne(wrapper);
//        Long typeId = null;
//        if (query == null) {
//            CommodityClassesType commodityClassesType = new CommodityClassesType();
//            commodityClassesType.setTypeName(classDTO.getType());
//            commodityClassesType.setDeleted(0);
//            commodityClassesType.setIsEnable(1);
//            commodityClassesType.setCreateTime(date);
//            commodityClassesType.setUpdateTime(date);
//            commodityClassesTypeMapper.insert(commodityClassesType);
//            typeId = commodityClassesType.getId();
//            System.out.println("=======typeId: " + typeId);
//        } else {
//            typeId = query.getId();
//        }
//
//        CommodityClasses classes = new CommodityClasses();
//        BeanUtils.copyProperties(classDTO, classes);
//        classes.setUrl(videoPath);
//        classes.setCover(coverPath);
//        classes.setTypeId(typeId);
//
//        // 后期需要修改
//        classes.setDeleted(0);
//        Random random = new Random();
//        Long businessId = (long) random.nextInt(9)+1;
//        classes.setBusinessId(businessId);
//        Integer sales = random.nextInt(99999)+1000;
//        classes.setSales(sales);
//        BigDecimal[] prices = {
//                new BigDecimal("298.00"),
//                new BigDecimal("299.99"),
//                new BigDecimal("199.98"),
//                new BigDecimal("159.00"),
//                new BigDecimal("250.00"),
//                new BigDecimal("278.50"),
//                new BigDecimal("223.98"),
//                new BigDecimal("199.99"),
//                new BigDecimal("188.88"),
//                new BigDecimal("88.88"),
//                new BigDecimal("99.99"),
//                new BigDecimal("125.50"),
//                new BigDecimal("648.00"),
//                new BigDecimal("366.00"),
//        };
//        int index = random.nextInt(prices.length);
//        classes.setOriginalPrice(prices[index]);
//        classes.setPresentPrice(prices[index].multiply(new BigDecimal("0.95")));
//        System.out.println("originalPrice -> "+classes.getOriginalPrice());
//        System.out.println("presentPrice -> "+classes.getPresentPrice());
//
//        classes.setCreateTime(date);
//        classes.setUpdateTime(date);
//
//        int rows = commodityClassesMapper.insert(classes);
//        if (rows == 0) {
//            if (videoPath != null) {
//                File video = new File(videoPath);
//                if (video.exists()) {
//                    video.delete();
//                }
//            }
//
//            if (coverPath != null) {
//                File cover = new File(coverPath);
//                if (cover.exists()) {
//                    cover.delete();
//                }
//            }
//
//            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
//                    "添加失败,服务器忙,请稍后重试");
//        }
//
//    }

    /**
     * 添加新的免费课
     * @param classDTO
     */
    @Override
    public void insert(RecommendAddClassDTO classDTO, File file) {
        // 获取保存文件的相对路径
        String videoPathDir = getVideoPathDir();
        String coverPathDir = getCoverPathDir();
        String videoName;
        String coverName;
        try {
            System.out.println("看看掉了几遍");
            videoName = FileUtils.upload(videoPathDir, FileUtils.fileToMultipartFile(file));
            String videoPath = videoPathDir + "/" + videoName;
            coverName = FileUtils.fetchFrame(videoPath, coverPathDir);
        } catch (IOException e) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "添加失败,服务器忙,请稍后重试");
        }

        RecommendClasses classes = new RecommendClasses();
        BeanUtils.copyProperties(classDTO, classes);
        classes.setUrl(videoName);
        classes.setPictures(coverName);
        // 后期需要修改
        classes.setIsChecked(0);
//        Random random = new Random();
//        Long businessId = (long) random.nextInt(9)+1;
//        classes.setBusinessId(businessId);

        LocalDateTime localDateTime = LocalDateTime.now();
        Date date = Date.from(localDateTime
                .atZone(ZoneId.systemDefault())
                .toInstant());
        classes.setCreateTime(date);
        classes.setUpdateTime(date);

        System.out.println("看看插入数据几遍");
        int rows = recommendClassesMapper.insert(classes);
        if (rows == 0) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "添加失败,服务器忙,请稍后重试");
        }

        RecommendClassesRedisDTO redisDTO = new RecommendClassesRedisDTO();
        BeanUtils.copyProperties(classes, redisDTO);
        BusinessInformation business =
                dubboBusinessInformationService.getById(classDTO.getBusinessId());
        redisDTO.setBusinessRating(business.getRating());
        redisDTO.setBusinessIntroduce(business.getIntroduce());
        redisDTO.setBusinessCover(business.getCoverUrl());

        String path = uploadVideoFolder + classes.getUrl();
        String durationTime = getDurationTime(path);
        redisDTO.setDurationTime(durationTime);

        redisDTO.setPictures(getUrl(
                staticVideoImgPatternPath, classes.getPictures()));
        redisDTO.setCreateTime(classes.getCreateTime());

        repository.save(redisDTO);
        repository.saveList(redisDTO);

    }

    /**
     * 删除免费课和存在服务器的文件
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        RecommendClasses classes = recommendClassesMapper.selectById(id);
        if (classes == null) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY,
                    "课程已删除");
        }

        // 删除数据库的信息
        int rows = recommendClassesMapper.deleteById(id);
        if (rows == 0) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY,
                    "删除失败,服务器忙,请稍后重试");
        }

        // 删除服务器的本地文件
        String videoPath = classes.getUrl();
        String coverPath = classes.getPictures();
        File video = new File(videoPath);
        File cover = new File(coverPath);
        if (!video.exists()) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY,
                    "课程已删除");
        }
        boolean result = video.delete();
        if (!result) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY,
                    "删除失败,服务器忙,请稍后重试");
        }
        cover.delete();

        repository.deleteList(id);
        repository.delete(id);
//        List<RecommendClassesRedisDTO> list = repository.getClassesDetailsList();
//        Iterator<RecommendClassesRedisDTO> iterator = list.iterator();
//        while (iterator.hasNext()){
//            RecommendClassesRedisDTO next = iterator.next();
//            Long name = next.getId();
//            if (name.equals(id)){
//                iterator.remove();
//                break;
//            }
//        }
//        repository.deleteList();
//        repository.saveList(list);
    }

    /**
     * 通过id返回免费课视频
     * @param id
     * @return
     */
    @Override
    public RecommendClassesVideoVO getClassVideoById(Long id) {
        RecommendClassesVideoVO videoVO = new RecommendClassesVideoVO();
        if (repository.hasClassesDetailsData(id)) {
            RecommendClassesRedisDTO redisDTO = repository.getClassesDetails(id);
            BeanUtils.copyProperties(redisDTO, videoVO);
            videoVO.setCreateTime(
                    TimeUtil.dateToString(redisDTO.getCreateTime(),
                            "yyyy-MM-dd HH:mm:ss"));
            return videoVO;
        }

        RecommendClasses classesById = recommendClassesMapper.selectById(id);
        if (classesById == null) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "服务器忙,请稍后重试");
        }
        BeanUtils.copyProperties(classesById, videoVO);
        videoVO.setCreateTime(
                TimeUtil.dateToString(classesById.getCreateTime(),
                        "yyyy-MM-dd HH:mm:ss"));
        videoVO.setUrl(getUrl(staticVideoPatternPath, classesById.getUrl()));

        BusinessInformation business = dubboBusinessInformationService
                .getById(classesById.getBusinessId());
        videoVO.setBusinessName(business.getName());

        RecommendClassesRedisDTO redisDTO = new RecommendClassesRedisDTO();
        BeanUtils.copyProperties(videoVO, redisDTO);
        redisDTO.setBusinessRating(business.getRating());
        redisDTO.setBusinessIntroduce(business.getIntroduce());
        redisDTO.setBusinessCover(business.getCoverUrl());

        String path = uploadVideoFolder + classesById.getUrl();
        String durationTime = getDurationTime(path);
        redisDTO.setDurationTime(durationTime);

        redisDTO.setPictures(getUrl(
                staticVideoImgPatternPath, classesById.getPictures()));
        redisDTO.setCreateTime(classesById.getCreateTime());

        repository.save(redisDTO);
        repository.saveList(redisDTO);

        return videoVO;
    }

    /**
     * 分页查询免费课
     * @return
     */
    @Override
    public JsonPage<RecommendClassesVO> getClasses(int pageNum, int pageSize) {
        if (!repository.hasClassesDetailsDataList()) {
            preloadCache();
            getClasses(pageNum, pageSize);
        }

//        PageHelper.startPage(pageNum, pageSize);
//        QueryWrapper<RecommendClasses> wrapper = new QueryWrapper<>();
//        wrapper.eq("is_checked", 1);
//
//        List<RecommendClasses> queryClasses =
//                recommendClassesMapper.selectList(wrapper);
//        JsonPage<RecommendClasses> page =
//                JsonPage.restPage(new PageInfo<>(queryClasses));
//        System.out.println("获取页码");
//        Integer resultPageNum = page.getPageNum();
//        Integer resultPageSize = page.getPageSize();
//        Integer resultTotalPages = page.getTotalPages();
//        Long resultTotalCount = page.getTotalCount();
//
//        System.out.println("得到商家ids");
//        List<Long> businessIds = new ArrayList<>();
//        for (RecommendClasses queryClass : queryClasses) {
//            businessIds.add(queryClass.getBusinessId());
//        }
//        Map<Long, BusinessInformation> businessMap = getBusinessMap(businessIds);
//
//        System.out.println("开始存储");
//        List<RecommendClassesVO> list = new ArrayList<>();
//        for (RecommendClasses queryClass : queryClasses) {
//            RecommendClassesVO classesVO = new RecommendClassesVO();
//            BeanUtils.copyProperties(queryClass, classesVO);
//
//            String path = uploadVideoFolder + queryClass.getUrl();
//            String durationTime = getDurationTime(path);
//            classesVO.setDurationTime(durationTime);
//
//            BusinessInformation business = businessMap.get(classesVO.getBusinessId());
//            classesVO.setBusinessName(business.getName());
//            classesVO.setBusinessRating(business.getRating());
//            classesVO.setBusinessIntroduce(business.getIntroduce());
//            classesVO.setBusinessCover(business.getCoverUrl());
//
//            classesVO.setPictures(getUrl(
//                    staticVideoImgPatternPath, classesVO.getPictures()));
//            classesVO.setCreateTime(queryClass.getCreateTime());
//
//            list.add(classesVO);
//        }
//        System.out.println("设置页码");
//        JsonPage<RecommendClassesVO> resultPage = JsonPage.restPage(new PageInfo<>(list));
//        resultPage.setPageNum(resultPageNum);
//        resultPage.setPageSize(resultPageSize);
//        resultPage.setTotalPages(resultTotalPages);
//        resultPage.setTotalCount(resultTotalCount);
//        return resultPage;
        List<RecommendClassesRedisDTO> classesList = repository.getClassesDetailsList();
        List<RecommendClassesRedisDTO> pagination =
                MemoryPaginationUtils.pagination(classesList, pageNum, pageSize);
        List<RecommendClassesVO> list = new ArrayList<>();
        for (RecommendClassesRedisDTO redisDTO : pagination) {
            RecommendClassesVO classesVO = new RecommendClassesVO();
            BeanUtils.copyProperties(redisDTO, classesVO);
            classesVO.setCreateTime(
                    TimeUtil.dateToString(redisDTO.getCreateTime(),
                            "MM-dd"));
            list.add(classesVO);
        }

        JsonPage<RecommendClassesVO> jsonPage =
                JsonPage.restPage(new PageInfo<>(list));
        jsonPage.setPageNum(pageNum);
        jsonPage.setPageSize(pageSize);
        jsonPage.setTotalPages(
                MemoryPaginationUtils.getTolPageNum(
                        repository.getListCount(), pageSize));
        jsonPage.setTotalCount((long) repository.getListCount());

        return jsonPage;
    }

    /**
     * 推荐四个随机免费课
     * @return
     */
    @Override
    public List<RecommendClassesVO> recommendClasses() {
        if (!repository.hasClassesDetailsDataList()) {
            preloadCache();
            recommendClasses();
        }

        int size = repository.getListCount();
        int pageSize = 10;
//        System.out.println("bound -> "+size / pageSize);
        Random random = new Random();
        int pageNum = random.nextInt(size / pageSize) + 1;
//        System.out.println("pageNum -> "+pageNum);
        List<RecommendClassesRedisDTO> classSimpleList = repository.getClassesDetailsList();
        List<RecommendClassesRedisDTO> recommendClassesVOS =
                MemoryPaginationUtils.pagination(
                        classSimpleList, pageNum, pageSize);

//        recommendClassesVOS.forEach(System.out::println);
        List<RecommendClassesRedisDTO> redisDTOList =
                MathUtil.random(recommendClassesVOS, 6);
        List<RecommendClassesVO> list = new ArrayList<>();
        for (RecommendClassesRedisDTO redisDTO : redisDTOList) {
            RecommendClassesVO classesVO = new RecommendClassesVO();
            BeanUtils.copyProperties(redisDTO, classesVO);
            classesVO.setCreateTime(
                    TimeUtil.dateToString(redisDTO.getCreateTime(),
                            "MM-dd"));
            list.add(classesVO);
        }

        return list;
//        QueryWrapper<RecommendClasses> wrapper = new QueryWrapper<>();
//        wrapper.eq("is_checked", 1);
//        Long size = recommendClassesMapper.selectCount(wrapper);
//        Random random = new Random();
//        int pageSize = random.nextInt((int) (size / 50));
//        List<RecommendClassesQueryVO> recommendClassesVOS = recommendClassesMapper
//                .selectPage(pageSize*50, 50);
//        List<RecommendClassesQueryVO> list = MathUtil.random(recommendClassesVOS, 4);
//        List<Long> businessIds = new ArrayList<>();
//        for (RecommendClassesQueryVO classesVO : list) {
//            businessIds.add(classesVO.getBusinessId());
//        }
//        Map<Long, BusinessInformation> businessMap = getBusinessMap(businessIds);
//
//        List<RecommendClassesVO> resultList = new ArrayList<>();
//        for (RecommendClassesQueryVO queryVO : list) {
//            RecommendClassesVO classesVO = new RecommendClassesVO();
//            BeanUtils.copyProperties(queryVO, classesVO);
//
//            String path = uploadVideoFolder + queryVO.getUrl();
//            String durationTime = getDurationTime(path);
//            classesVO.setDurationTime(durationTime);
//
//            classesVO.setPictures(
//                    getUrl(staticVideoImgPatternPath,
//                            queryVO.getPictures()));
//            BusinessInformation business = businessMap.get(
//                    queryVO.getBusinessId());
//            classesVO.setBusinessName(business.getName());
//            classesVO.setBusinessIntroduce(business.getIntroduce());
//            classesVO.setBusinessRating(business.getRating());
//            classesVO.setBusinessCover(business.getCoverUrl());
//
//            resultList.add(classesVO);
//        }
//
//        return resultList;
    }

    /**
     * 下载免费课视频
     * @param id
     * @param response
     */
    @Override
    public void download(Long id, HttpServletResponse response) {
        RecommendClasses classes = recommendClassesMapper.selectById(id);
        String filePath = uploadVideoFolder + classes.getUrl();
        String fileName = classes.getTitle();

        System.out.println("filePath -> "+filePath);
        System.out.println("fileName -> "+fileName);
        try {
            FileUtils.download(fileName, filePath, response);
        } catch (IOException e) {
//            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
//                    "发生未知错误,下载失败");
            e.printStackTrace();
        }

    }

    /**
     * 缓存预热
     */
    @Override
    public void preloadCache() {
        System.out.println("==========开始进行缓存预热==========");
        repository.delete();
        repository.deleteList();

        QueryWrapper<RecommendClasses> wrapper = new QueryWrapper<>();
        wrapper.eq("is_checked", 1);
        List<RecommendClasses> queryClasses = recommendClassesMapper.selectList(wrapper);
        List<Long> businessIds = new ArrayList<>();
        for (RecommendClasses queryClass : queryClasses) {
            businessIds.add(queryClass.getBusinessId());
        }
        businessIds = businessIds.stream().distinct().collect(Collectors.toList());
        Map<Long, BusinessInformation> businessMap = getBusinessMap(businessIds);

        List<RecommendClassesRedisDTO> list = new ArrayList<>();
        for (RecommendClasses queryClass : queryClasses) {
            // 存储基本信息
            RecommendClassesRedisDTO redisDTO = new RecommendClassesRedisDTO();
            BeanUtils.copyProperties(queryClass, redisDTO);

            String path = uploadVideoFolder + queryClass.getUrl();
            String durationTime = getDurationTime(path);
            redisDTO.setDurationTime(durationTime);

            redisDTO.setPictures(getUrl(
                    staticVideoImgPatternPath, redisDTO.getPictures()));
            redisDTO.setCreateTime(queryClass.getCreateTime());

            redisDTO.setUrl(getUrl(staticVideoPatternPath, queryClass.getUrl()));

            BusinessInformation business = businessMap.get(queryClass.getBusinessId());
            redisDTO.setBusinessName(business.getName());
            redisDTO.setBusinessRating(business.getRating());
            redisDTO.setBusinessIntroduce(business.getIntroduce());
            redisDTO.setBusinessCover(business.getCoverUrl());

            repository.save(redisDTO);
            list.add(redisDTO);
        }

        repository.saveList(list);

    }

    /**
     * 得到储存视频的目录位置的方法
     * @return 返回目录位置
     */
    private String getVideoPathDir() {
        ConfigUtils configUtils = new ConfigUtils(
                "/config/pathConfig.config");

        return configUtils.getString("videoPath");
    }

    /**
     * 得到储存视频封面图片的目录位置的方法
     * @return 返回目录位置
     */
    private String getCoverPathDir() {
        ConfigUtils configUtils = new ConfigUtils(
                "/config/pathConfig.config");

        return configUtils.getString("coverPath");
    }

    /**
     * 得到静态资源地址
     * @param staticPath
     * @param path
     * @return
     */
    private String getUrl(String staticPath, String path) {
        String url = null;
        staticPath = staticPath.split("\\*\\*")[0];

        //            url = "http://"+ IpUtils.getLocalIp() + ":" + port
//              "http://"+ IpUtils.getLocalIp() + ":" + port
        url= staticPath + path;

        return url;
    }

    /**
     * 返回存有商家名字的map的方法
     * @param businessIds
     * @return
     */
    private Map<Long, BusinessInformation> getBusinessMap(List<Long> businessIds) {
        businessIds = businessIds.stream().distinct().collect(Collectors.toList());
        List<BusinessInformation> business =
                dubboBusinessInformationService.listByIds(businessIds);
        Map<Long, BusinessInformation> businessMap = new HashMap<>();
        for (BusinessInformation b : business) {
            businessMap.put(b.getId(), b);
        }
        return businessMap;
    }

    /**
     * 返回视频时长
     * @param path 路径地址
     * @return hh:mm:ss或mm:ss
     */
    private String getDurationTime(String path) {
        long mp4Duration = FileUtils.getMp4Duration(path);

        String hour = (mp4Duration / 3600) + "";
        hour = hour.length()>1 ? hour : "0"+hour;
        mp4Duration = mp4Duration % 3600;

        String min = (mp4Duration / 60) + "";
        min = min.length()>1 ? min : "0"+min;
        mp4Duration = mp4Duration % 60;

        String sec = mp4Duration + "";
        sec = sec.length()>1 ? sec : "0"+sec;

        return "00".equals(hour) ? min+":"+sec : hour+":"+min+":"+sec;
    }

}
